package robots;

import java.util.ArrayList;
import java.util.HashMap;

import maze.Barcode;
import maze.Coordinate;
import maze.Direction;
import maze.Location;
import maze.Maze;
import pacman.Game;
import pacman.protocol.GhostProtocolSender;
import pacman.protocol.OwnGhostProtocolProcessor;
import robots.analyser.DistanceToWall;
import robots.analyser.SectorAnalyser;
import robots.analyser.SectorAnalyserV1;
import robots.behaviour.Explorer;
import robots.behaviour.MazeCorrector;
import robots.behaviour.PacmanFinder;
import robots.behaviour.Strategy;
import robots.correction.RobotCorrector;
import sensors.IRSensor;
import sensors.LightSensor;
import sensors.UltrasonicSensor;
import bluetoothCommunication.Communicator;



public abstract class OwnGhost extends Ghost{
	
	private IRSensor infraredSensor;
	private LightSensor lightSensor;
	private UltrasonicSensor ultrasonicSensor;
	private RobotCorrector robotCorrector;
	public int xOffsetSensor;
	public int yOffsetSensor;
	private boolean wasNextToPacman = false;
	
	public SectorAnalyser sectorAnalyser = new SectorAnalyserV1();
	
	/**
	 * The location where this robot thinks it is.
	 */
	private Location location;
	
	/**
	 * A list of ghosts to whom this ghost send a PING.
	 */
	private ArrayList<Ghost> waitingForPONG;
	
	/**
	 * The rotation of this robot
	 */
	private int rotation;
	
	/**
	 * relative rotation tov de robot, positief is naar links
	 */
	private int sensorRotation; 
	
	/**
	 * Responsible for sending RabbitMQ messages
	 */
	public GhostProtocolSender protocolSender;
	
//	/**
//	 * The last coordinate where this ghost has seen pacman.
//	 * This is recorded here because this position is the one in this ghost's own maze, not the real one.
//	 */
//	private Coordinate coordinatePacman;
	
	/**
	 * This robot's default strategy
	 */
	protected Strategy defaultStrategy;
	
	/**
	 * This robot's current strategy
	 */
	protected Strategy currentStrategy;
	
	/**
	 * This robot's secondary strategy;
	 */
	protected Strategy secondaryStrategy;

	/**
	 * True while the ghost isn't standing still
	 */
	public boolean isTravelling;
	
	/**
	 * TODO: commentaar schrijven hiervoor
	 */
	protected boolean inBarcodeState;
	
	/**
	 * Array containing the positions of the other ghosts in this game
	 */
	private Coordinate[] ghostPositionsArr = {new Coordinate(0,0),new Coordinate(0,0),new Coordinate(0,0),new Coordinate(0,0)};
	
	/**
	 * Creates a new ownGhost on Location 0,0
	 */
	public OwnGhost(Game game, String name){
		this(game, new Location(20,20), name);		
	}
	
	/**
	 * Creates a new ownGhost on a given location
	 */
	public OwnGhost(Game game, Location loc, String name){
		super(null, game, name);
		setCoordinate(getMaze().getCoordinateOfLocation(loc)); //vuil
		protocolSender = new GhostProtocolSender(this);
		//Overschrijf de processor gezet in GhostConstructor
		protocolProcessor = new OwnGhostProtocolProcessor(this);
		setLocation(loc);
		defaultStrategy = new Explorer(getMaze());
		secondaryStrategy =  new MazeCorrector(getMaze());
		currentStrategy = defaultStrategy;
		setWaitingForPONG(new ArrayList<Ghost>(Game.NUMBEROFGHOSTS));
	}
	
	/**
	 * ------------------
	 * 		METHODES
	 * ------------------
	 * @param correction TODO
	 */

	public abstract void travel(int distance, boolean correction, boolean interrupt);
	
	public abstract void rotate(int degrees, boolean correction);
	
	public abstract void setSpeed(int speed);
	protected abstract void registerPacman();
	
	/**
	 * Returns the integer value of this Ghost's direction.
	 * "Hierbij wordt de waarde 
	 * 1 gebruikt voor noord naar zuid,  == ZUID
	 * 2 voor oost naar west, 			 == WEST
	 * 3 voor zuid naar noord, 			 == NOORD
	 * 4 voor west naar oost."			 == OOST
	 */
	public Direction generateDirection() {
		int rot = getRotation() % 360;
		rot = rot < 0 ? (360 - Math.abs(rot)) : rot;

		if (rot > 45 && rot < 135) {
			return Direction.NORTH;
		} else if (rot >= 135 && rot < 225) {
			return Direction.WEST;
		} else if (rot >= 225 && rot < 315) {
			return Direction.SOUTH;
		} else {
			return Direction.EAST;
		}
	}
	
	
	
	/**
	 * Returns the integer value of this Ghost's direction.
	 * "Hierbij wordt de waarde 
	 * 1 gebruikt voor noord naar zuid,  == ZUID
	 * 2 voor oost naar west, 			 == WEST
	 * 3 voor zuid naar noord, 			 == NOORD
	 * 4 voor west naar oost."			 == OOST
	 */
	public Direction generateDirection(int rotation) {
		int rot = rotation % 360;
		rot = rot < 0 ? (360 - Math.abs(rot)) : rot;
		Direction direction;
		if (rot > 45 && rot < 135) {
			direction = Direction.NORTH;
		} else if (rot >= 135 && rot < 225) {
			direction = Direction.WEST;
		} else if (rot >= 225 && rot < 315) {
			direction = Direction.SOUTH;
		} else {
			direction = Direction.EAST;
		}
		return direction;
	}
	
	/**
	 * Returns the integer value of this Ghost's direction.
	 * Hierbij wordt de waarde 
	 * 1 gebruikt voor noord naar zuid,  == ZUID
	 * 2 voor oost naar west, 			 == WEST
	 * 3 voor zuid naar noord, 			 == NOORD
	 * 4 voor west naar oost.			 == OOST
	 */
	public int generateDirectionNumber() {
		int rot = getRotation() % 360;
		rot = rot < 0 ? (rot+360) : rot; //used to be 360 - Math.abs(rot)

		if (rot > 45 && rot < 135) {
			return 3;
		} else if (rot >= 135 && rot < 225) {
			return 2;
		} else if (rot >= 225 && rot < 315) {
			return 1;
		} else {
			return 4;
		}
	}
	
	/**
	 * Writes walls in the local maze. Given Map must contain an entry for every direction!
	 */
	public void writeWalls(HashMap<Direction, DistanceToWall> sectorWalls,	Coordinate co) {
		Maze maze = this.getMaze();
		int rotation = this.getRotation();
		Direction direction = this.generateDirection(rotation);
		Direction oppositeDir = direction.opposite();
		if(maze.read(co.getX(), co.getY(), oppositeDir, true)==0)
			maze.write(co.getX(), co.getY(), oppositeDir,
					(char) sectorWalls.get(oppositeDir).WallType, true);
		if(!oppositeDir.equals(Direction.NORTH)){
			maze.write(co.getX(), co.getY(), Direction.NORTH,
				(char) sectorWalls.get(Direction.NORTH).WallType, true);
		}
		if(!oppositeDir.equals(Direction.EAST)){
			maze.write(co.getX(), co.getY(), Direction.EAST,
				(char) sectorWalls.get(Direction.EAST).WallType, true);
		}
		if(!oppositeDir.equals(Direction.SOUTH)){
			maze.write(co.getX(), co.getY(), Direction.SOUTH,
				(char) sectorWalls.get(Direction.SOUTH).WallType, true);
		}
		if(!oppositeDir.equals(Direction.WEST)){
			maze.write(co.getX(), co.getY(), Direction.WEST,
				(char) sectorWalls.get(Direction.WEST).WallType, true);
		}
	}
	
	public void travelToNextSector(CorrectionMode mode, int distance) {

		if(this instanceof RealGhost){
			robotCorrector.lineCorrect();
			travel(distance,false, true);
			registerPacman();	
			rotateSensorMotor(90);
			int begin = getUltrasonicValue();
			rotateSensorMotor(-90);
			Direction robotDirection = generateDirection();
			if(begin<=25){
				robotCorrector.getInMiddle(robotDirection, robotDirection.left(), begin);
			}
			return;
		}
		int sign = 0;
		if(mode==CorrectionMode.LEFT)
			sign=1;
		else if (mode == CorrectionMode.RIGHT)
			sign=-1;
		rotateSensorMotor(sign * 90);
		int begin = getUltrasonicValue();
		Direction robotDirection = generateDirection();
		if(begin<=25&&mode!=CorrectionMode.NONE){
			robotCorrector.getInMiddle(robotDirection, modeToDirection(mode, robotDirection), begin);
		}
		
		begin = getUltrasonicValue();
//		if(mode!=CorrectionMode.LEFT)
//			robotCorrector.lineCorrect();
		travel(distance,false, true);
		
		int end = this.getUltrasonicValue();
		resetSensorMotor();
		
		robotCorrector.correctAngle(begin, end, sign);
		
		if(end<=25&&mode!=CorrectionMode.NONE){
			robotDirection = generateDirection();
			robotCorrector.getInMiddle(robotDirection, modeToDirection(mode, robotDirection), end);
		}
		registerPacman();		
	}
	
	private Direction modeToDirection(CorrectionMode mode, Direction robotDirection){
		switch(mode){
		case LEFT: return robotDirection.left();
		case RIGHT: return robotDirection.right();
		case NONE: return null;
		default: return null;
		}
			
	}
	
	public int getUltrasonicValue(){
		return interpretPositionSensor(sensorRotation, xOffsetSensor, yOffsetSensor, this.getUltrasonicSensor().getDistance());
	}
	
	private int interpretPositionSensor(int sensorRotation, int xOffsetSensor, int yOffsetSensor, int distance) {
		int result= distance;
		int sensorRot = (sensorRotation%360+360)%360;
		switch(sensorRot){
		case 0: result+=xOffsetSensor;
		break;
		case 90: result+=yOffsetSensor;
		break;
		case 180: result-=xOffsetSensor;
		break;
		case 270: result-=yOffsetSensor;
		break;
		}
		return result;
	}

	protected abstract void scheduleBarcodeAnalyserTask();
	
	public void run() {
		scheduleBarcodeAnalyserTask();
		
		while(true){
			currentStrategy=defaultStrategy;
			while (currentStrategy != null) {
				if (!isTravelling){ 
					if(!this.getMaze().getCoordinateOfLocation(this.getLocation()).equals(previousCoordinate))
						exploreSector();
					previousCoordinate=this.getMaze().getCoordinateOfLocation(this.getLocation());
					updateStrategy();
				}
			}
			while(checkIRSensor());
		}
	}
	private boolean checkIRSensor(){
		return this.infraredSensor.getDirection()!=0;
	}
	
	protected abstract void victory();
	
	protected void exploreSector(){
		Maze maze = this.getMaze();
		Coordinate currentCoordinate = maze.getCoordinateOfLocation(this.getLocation());
		if (!maze.hasThisSectorExplored(currentCoordinate)||currentStrategy.exploreEverything()) {
			HashMap<Direction, DistanceToWall> sectorWalls = sectorAnalyser.ExploreSector(this);
			writeWalls(sectorWalls, currentCoordinate);
			if(this instanceof VirtualGhost)
				robotCorrector.correctToWalls(sectorWalls, generateDirection());

			//vanaf hier protocolshizzle
			Direction[] directions = {Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST};
			int walls[] = new int[4];			
			for(int h=0; h<directions.length; h++)
			{
				int wallType = sectorWalls.get(directions[h]).WallType;
				if(wallType == 1)
					walls[h] = 1;
				else
					walls[h] = 0;
			}
			/**
			 * String message = "JOIN\n";
				channel.basicPublish("ORANJE", "", null, message.getBytes());
			 */
			int[] nozw = new int[4];
			nozw = generateInformation(walls, directions);
			protocolSender.sendDISCOVER(nozw[0], nozw[1], nozw[2], nozw[3]);
			resetSensorMotor();
		}
	}
	protected Coordinate previousCoordinate=new Coordinate(1,1);
	protected void updateStrategy() {
		Maze maze = this.getMaze();
		Coordinate currentCoordinate = maze.getCoordinateOfLocation(this.getLocation());
		for(int i = 0; i<matchedGhosts.length; i++) {
			for(Ghost g : this.getGame().getGhosts()) {
				if(matchedGhosts[i].getName().equals(g.getName())) {
					Coordinate ghostPosition = this.getGame().getGhostPositions().get(g);
					ghostPositionsArr[i] = this.getMazeOnName(g.getName()).reverseTransform(ghostPosition);
					//System.out.println(this.getName()+": "+ g.getName()+" "+this.getGame().getGhostPositions().get(g));
				}
			}
		}
		/*if((currentStrategy instanceof MazeCorrector)){
			currentStrategy=defaultStrategy;
		}*/
		Maze[] matchingMazes = new Maze[matchedGhosts.length];
		for (int i = 0; i < matchedGhosts.length; i++) {
			Ghost ghost = matchedGhosts[i];
			matchingMazes[i]=this.mazesOtherRobots.get(ghost.getName());
		}
		Direction next= currentStrategy.nextDirection(getLocation(), matchingMazes, this.ghostPositionsArr);
		boolean returnedNull = next==null;
		if((currentStrategy instanceof Explorer) && returnedNull){
			if(this.hasFoundPacman()){
				currentStrategy=new PacmanFinder(getMaze());
				currentStrategy.setCoordinatePacman(coordinatePacman);
				wasNextToPacman = false;
			}
			else{
				currentStrategy=secondaryStrategy;
				((MazeCorrector)secondaryStrategy).setPreviousDirection(this.generateDirection());
				previousCoordinate = null;
				wasNextToPacman = false;
			}
		}
		else if((currentStrategy instanceof PacmanFinder)&& returnedNull){
			if(!this.nextToPacman()){
				currentStrategy=secondaryStrategy;
				if(wasNextToPacman)
					((MazeCorrector)secondaryStrategy).setPreviousDirection(this.generateDirection().left());
				else
					((MazeCorrector)secondaryStrategy).setPreviousDirection(this.generateDirection());
				previousCoordinate = null;
				wasNextToPacman = false;
			}
			else{
				wasNextToPacman = true;
				facePacman();
				
			}
		}
		else if((currentStrategy instanceof MazeCorrector)){
			currentStrategy=defaultStrategy;
			wasNextToPacman = false;
		}
		Direction current = generateDirection();
		if (next == current.left()) {
			this.rotate(90, false);
		} else if (next == current.opposite()) {
			this.rotate(-180, false);
		} else if (next == current.right()) {
			this.rotate(-90, false);
		}
		registerPacman();
		if((currentStrategy instanceof PacmanFinder) && ((PacmanFinder)currentStrategy).pacmanCaught()) {
			currentStrategy=null;
			System.out.println("You'll always remember this as the day we (almost) caught Pac Sparrow!");
			wasNextToPacman = true;
			facePacman();
			victory();
			return;
		}
		if(next==null) return;
		//pacman staat in de richting dat je wil rijden
		if(this.hasFoundPacman() && getCoordinatePacman().equals(Coordinate.getCoordinateInDirection(getMaze().getCoordinateOfLocation(this.getLocation()), this.generateDirection()))){
			return;
		}
		
		CorrectionMode mode=CorrectionMode.NONE;
		if (maze.read(currentCoordinate.getX(), currentCoordinate.getY(),next.left(), true) == 1) 
			mode=CorrectionMode.LEFT;
		else if(maze.read(currentCoordinate.getX(),currentCoordinate.getY(), next.right(), true) == 1)
			mode=CorrectionMode.RIGHT;
		
		
		//TODO: zeer vuil, herwerken
		checkBarcodeState();
		if(!inBarcodeState){
			travelToNextSector(mode, 40);
		}
		else{
			if(this instanceof VirtualGhost){
				((VirtualGhost) this).getBarcodeAnalyserTask().barcodeAnalyser.readings.clear();
				travel(-15,true, false);
				((VirtualGhost) this).getBarcodeAnalyserTask().barcodeAnalyser.readings.clear();
				travelToNextSector(CorrectionMode.NONE, 55);
				return;
			}
			Location bcLocation=getLocation();
			travel(-20,false, false);
			int previousSpeed=((RealGhost)this).getCommunicator().getSpeed();
			setSpeed(200);
			travelToNextSector(CorrectionMode.NONE, 60);
			setSpeed(previousSpeed);
			String bc=((RealGhost)this).lookForBarcode();
			if (!bc.equals("")) {
				System.out.println("Barcode detected: " + bc);
				sendAndAddBarcode(bc, bcLocation);
			}
			checkBarcodeState();
			inBarcodeState=false;
		}
		
		
//		if (maze.read(currentCoordinate.getX(), currentCoordinate.getY(),next.left(), true) == 1) {
//			if (getCommunicator() != null)
//				travelToNextSector(CorrectionMode.LEFT,40);
//			else
//				this.travel(40, false);
//		} else if (maze.read(currentCoordinate.getX(),
//				currentCoordinate.getY(), next.right(), true) == 1) {
//			if (getCommunicator() != null)
//				travelToNextSector(CorrectionMode.RIGHT,40);
//			else
//				this.travel(40, false);
//		} else {
//			this.travel(40, false);
//		}
	}
	private boolean nextToPacman(){
		if(!hasFoundPacman()) return false;
		Coordinate coord = this.getCoordinate();
		Direction dir = coord.getDirectionOfCoordinate(this.getCoordinatePacman());
		if(dir != null && this.getMaze().read(coord.x, coord.y, dir, true)==2)
			return true;
		return false;
	}
	private void facePacman(){
		Coordinate coord = this.getCoordinate();
		Direction dir = coord.getDirectionOfCoordinate(this.getCoordinatePacman());
		Direction current = generateDirection();
		if (dir == current.left()) {
			this.rotate(90, false);
		} else if (dir == current.opposite()) {
			this.rotate(-180, false);
		} else if (dir == current.right()) {
			this.rotate(-90, false);
		}
	}
	
	@Override
	public void lastPreparations(){
		for(Ghost otherGhost: getGame().getOtherGhostsThan(getName())){
			addOtherRobotMaze(otherGhost);
		}
		if(getGame().crashedGame){ //Bij een gecrashte game alle oude info opnieuw opvragen om zo direct verder te kunnen
			for(Ghost otherGhost: getGame().getOtherGhostsThan(getName())){
				protocolSender.sendSHOWMAP(otherGhost.getName());
			}
		}
		readySetGo = true;
	}
	
	//TODO: zeer vuil, herwerken
	private void checkBarcodeState() {
		if(this instanceof RealGhost){
			RealGhost ghost = (RealGhost) this;
			Communicator comm = ghost.getCommunicator();
			if(comm != null)
			{
				inBarcodeState = comm.hasBlackListValues();
			}
			if(!isValidBarcodeSector()){
				inBarcodeState=false;
			}
		}
		if(this instanceof VirtualGhost){
			if(inBarcodeState = ((VirtualGhost) this).getBarcodeAnalyserTask().barcodeAnalyser.hasBlackValues()){
				System.out.println("blackvalues detected");
				inBarcodeState=true;
			}
		}
	}
	
	private boolean isValidBarcodeSector() {
		Coordinate coord=this.getCoordinate();
		int wallLeft=this.getMaze().read(coord.getX(), coord.getY(), this.generateDirection().left(), true);
		int wallRight=this.getMaze().read(coord.getX(), coord.getY(), this.generateDirection().right(), true);
		int wallFront=this.getMaze().read(coord.getX(), coord.getY(), this.generateDirection(), true);
		int wallBack=this.getMaze().read(coord.getX(), coord.getY(), this.generateDirection().opposite(), true);
		if(wallLeft==1&&wallRight==1&&wallFront==2&&wallBack==2)
			return true;
		return false;
	}

	public void resetSensorMotor() {
		setSensorRotation(0);
	}

	private int[] generateInformation(int[] walls, Direction[] directions) {
		int[] nozw = new int[4];
		int indexNorth = -1;
		for (int i = 0; i < walls.length; i++) {
			if (directions[i] == Direction.NORTH) {
				indexNorth = i;
			}
		}
		switch (indexNorth) {
		case (0):
			return walls;
		case (1):
			return shiftArray(walls, 3);
		case (2):
			return shiftArray(walls, 2);
		case (3):
			return shiftArray(walls, 1);
		}
		return nozw;
	}

	private int[] shiftArray(int[] walls, int amount) {
		for (int j = 0; j < amount; j++) {
			int a = walls[walls.length - 1];
			int i;
			for (i = walls.length - 1; i > 0; i--)
				walls[i] = walls[i - 1];
			walls[i] = a;
		}
		return walls;
	}

	public abstract void rotateSensorMotor(int degrees);

	/**
	 * Returns the code representation of a barcode.
	 * "Een binaire barcode van de vorm abcdef (waarbij elke
		letter een 1 of een 0 voorstelt)1 wordt voorgesteld door het gehele getal
		25 · a + 24 · b + 23 · c + 22 · d + 21 · e + 20 · f ."
	 * @param barcode
	 * @return
	 */
	public int generateBarcodeCode(String barcode) {
		if (barcode.equals(""))
			return 0;
		int code = 0;
		int macht = 0;
		for (int i = (barcode.length() - 2); i >= 0; i--) {//dont process last zero
			int waarde = Character.getNumericValue(barcode.charAt(i));
			code += waarde * Math.pow(2, macht);
			macht++;
		}
		return code;
	}
	
	void sendAndAddBarcode(String bc, Location location) {
		int barcodeCode = generateBarcodeCode(bc);
		if (barcodeCode != 0) {
			Coordinate coord = getMaze().getCoordinateOfLocation(location);
			
			// onderstaande is voor barcodes te verwijderen als we er willen toevoegen (dit gebeurt als er op deze coordinaat al een barcode staat (van ons) en we willen er een andere zetten)
			// dit is in de veronderstelling dat in maze van getMaze() enkel onze barcodes staan. 
			ArrayList<Barcode> barcodes=getMaze().getBarcodes();
//			for (int i = 0; i < barcodes.size(); i++) {
//				Barcode barcode= barcodes.get(i);
//				if(barcode.getPosition().getX()==coord.getX()&&barcode.getPosition().getY()==coord.getY()&&!barcode.getCode().equals(bc)){
//					getMaze().removeBarcode(barcode);
//				}
//			}
			protocolSender.sendBARCODEAT(coord, barcodeCode, generateDirectionNumber());
			//if dirction is horizontal -> 1 else 0`
			System.out.println("add barcode:" + bc);
			getMaze().addBarcode(new Coordinate(coord.getX(), coord.getY()), bc,generateDirectionNumber());
		}
	}
	

	public void handleCrashedGhost(String newName, String newVersion) {
		if(getWaitingForPONG().size() == 0){
			System.err.println("Iedereen antwoorde, niemand is gecrashed");
			return;
		}else{
			Ghost crashedGhost = getWaitingForPONG().get(0);
			System.out.println("Gecrashte ghost gevonden:" + crashedGhost.getName());
			getGame().resetCrashedGhost(crashedGhost, newName, newVersion);
			
			//TODO: klopt misschien niet 100%. Geval waar 2 ghosts tegelijk crashen wordt niet verwerkt
			//WaitingforPONG leegmaken
			setWaitingForPONG(new ArrayList<Ghost>(Game.NUMBEROFGHOSTS));
		}
	}
	
	/**
	 * ------------------
	 * GETTERS EN SETTERS
	 * ------------------
	 */
	
	@Override
	public void setCoordinatePacman(Coordinate pacman){
		coordinatePacman=pacman;
		foundPacman(true);
		if(currentStrategy!=null)
			currentStrategy.setCoordinatePacman(pacman);
	}
	
	public UltrasonicSensor getUltrasonicSensor() {
		return ultrasonicSensor;
	}
	protected void setUltrasonicSensor(UltrasonicSensor ultrasonicSensor) {
		this.ultrasonicSensor = ultrasonicSensor;
	}
	public LightSensor getLightSensor() {
		return lightSensor;
	}
	protected void setLightSensor(LightSensor lightSensor) {
		this.lightSensor = lightSensor;
	}

	public IRSensor getInfraredSensor() {
		return infraredSensor;
	}
	protected void setInfraredSensor(IRSensor infraredSensor) {
		this.infraredSensor = infraredSensor;
	}
	
	protected void setRobotCorrector(RobotCorrector corr)
	{
		this.robotCorrector = corr;
	}
	
	public Strategy getCurrentStrategy(){
		return currentStrategy;
	}
	public void setCurrentStrategy(Strategy currentStrategy){
		this.currentStrategy = currentStrategy;
	}

	public Strategy getSecondaryStrategy(){
		return secondaryStrategy;
	}
	private void setSecondaryStrategy(Strategy secondaryStrategy) {
		this.secondaryStrategy = secondaryStrategy;
	}

	public Strategy getDefaultStrategy() {
		return defaultStrategy;
	}
	private void setDefaultStrategy(Strategy defaultStrategy) {
		this.defaultStrategy = defaultStrategy;
	}
	
	public Location getLocation() {
		return location;
	}
	public void setLocation(Location location) {
		this.location = location;
	}

	public int getRotation() {
		return rotation;
	}
	public void setRotation(int rotation) {
		this.rotation = rotation;
	}
	public int getSensorRotation() {
		return sensorRotation;
	}
	
	protected void setSensorRotation(int sensorRotation) {
		this.sensorRotation = sensorRotation;
	}
	
	public ArrayList<Ghost> getWaitingForPONG() {
		return waitingForPONG;
	}
	private void setWaitingForPONG(ArrayList<Ghost> waitingForPONG) {
		this.waitingForPONG = waitingForPONG;
	}
	@Override
	public Coordinate getCoordinate() {
		return this.getMaze().getCoordinateOfLocation(this.getLocation());
	}
	public Coordinate[] getGhostPositions(){
		return this.ghostPositionsArr;
	}
}

